package top.lingkang.finalpool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.LinkedBlockingQueue;

public class FinalPool {
    private final Logger logger = LoggerFactory.getLogger(FinalPool.class);
    private FinalPoolConfig finalPoolConfig;
    private int maxConnectionNumber = 10;
    private static LinkedBlockingQueue<FinalDataSource> busy = null;
    private static LinkedBlockingQueue<FinalDataSource> idle = null;

    /**
     * 获取数据源
     */
    public FinalDataSource getDataSource() throws Exception {
        FinalDataSource ipoll = idle.poll();
        // 判断当前连接是否断开了
        if (ipoll != null) {
            boolean closed = ipoll.getConnection().isClosed();
            if (closed) {
                logger.warn("连接池存在断开的连接，抛弃：{}", ipoll.getConnection().toString());
                while (true) {
                    ipoll = idle.poll();
                    if (ipoll == null || !ipoll.getConnection().isClosed())
                        break;
                    logger.warn("连接池存在断开的连接，抛弃：{}", ipoll.getConnection().toString());
                }
            }

            // 添加到忙碌
            busy.put(ipoll);
            return ipoll;
        }

        // 超出线程池数量
        if (busy.size() == maxConnectionNumber) {
            logger.warn("超出线程池数量，等待其他连接池释放");
            return idle.take();
        }

        // 创建新的链接
        FinalDataSource dataSource = createFinalDataSource();
        busy.put(dataSource);
        return dataSource;
    }

    /**
     * 释放数据源
     */
    public void releaseDataSource(FinalDataSource source) throws Exception {
        if (source != null){
            idle.put(busy.poll());
        }
    }

    /**
     * 创建数据库连接
     */
    private FinalDataSource createFinalDataSource() {
        String driver;
        if (!FinalPoolUtils.isEmpty(finalPoolConfig.getDriver())) {
            driver = finalPoolConfig.getDriver();
        } else {
            driver = FinalPoolUtils.getDriver(finalPoolConfig.getUrl());
            if (FinalPoolUtils.isEmpty(driver)) {
                logger.error("Driver not found!");
                new IllegalAccessException("Driver class 未找到");
            }
        }
        try {
            Class.forName(driver);
            // 登录超时时间
            DriverManager.setLoginTimeout(finalPoolConfig.getLoginOutTime());
            // 连接
            Connection connection = DriverManager.getConnection(
                    finalPoolConfig.getUrl(),
                    finalPoolConfig.getUsername(),
                    finalPoolConfig.getPassword());
            FinalDataSource source = new FinalDataSource();
            source.setConnection(connection);
            return source;
        } catch (Exception e) {
            logger.error("连接数据库失败！", e);
            new IllegalAccessError(e.getMessage());
        }
        return null;
    }


    /**
     * 初始化连接池
     */
    public void init() {
        logger.info("FinalPool init start...");
        if (finalPoolConfig == null) {
            new IllegalAccessException("未配置finalPoolConfig");
        }
        if ((maxConnectionNumber = finalPoolConfig.getMaxConnectionNumber()) <= 0) {
            finalPoolConfig.setMaxConnectionNumber(10);
            maxConnectionNumber = 10;
        }
        busy = new LinkedBlockingQueue<>(maxConnectionNumber);
        idle = new LinkedBlockingQueue<>(maxConnectionNumber);
        if (finalPoolConfig.getLoginOutTime() == 0) {
            finalPoolConfig.setLoginOutTime(30);
        }
        if (finalPoolConfig.getMinIdle() == 0) {
            finalPoolConfig.setMinIdle(1);
        }
        if (finalPoolConfig.getSurvivalTime() == 0) {
            finalPoolConfig.setSurvivalTime(1000 * 60000 * 30);
        } else if (finalPoolConfig.getSurvivalTime() < 1000) {
            new IllegalAccessError("survivalTime最小值为1000");
        }

        // 定时清理存活数据源
        new Timer().schedule(
                new ClearIdleTask(
                        finalPoolConfig.getSurvivalTime(),
                        finalPoolConfig.getMinIdle()
                ),
                0, finalPoolConfig.getSurvivalTime());
        logger.info("FinalPool finish! please use FinalPoolUtils");
    }

    /**
     * 定时清理连接池
     */
    class ClearIdleTask extends TimerTask {
        private long survivalTime;
        private int minIdle;

        public ClearIdleTask(long survivalTime, int minIdle) {
            this.survivalTime = survivalTime;
            this.minIdle = minIdle;
        }

        @Override
        public void run() {
            if (idle.isEmpty()) {
                return;
            }
            long endTime = System.currentTimeMillis() - survivalTime;
            if (idle.peek().getLastGetTime() > endTime) {
                return;
            }
            // 关闭超过存活的数据源
            for (int i = 0; i < idle.size(); i++) {
                FinalDataSource poll = idle.poll();
                if (poll.getLastGetTime() > endTime) {
                    try {
                        idle.put(poll);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    poll.closeConnection();
                }
            }
        }
    }

    public FinalPoolConfig getFinalPoolConfig() {
        return finalPoolConfig;
    }

    public void setFinalPoolConfig(FinalPoolConfig finalPoolConfig) {
        this.finalPoolConfig = finalPoolConfig;
    }


}
